from flask import Flask, request, jsonify  
from werkzeug.security import generate_password_hash, check_password_hash  
import pymysql.cursors  
import jwt  
from datetime import datetime, timedelta  
import re  
from functools import wraps  
from flask_cors import CORS  

# 初始化Flask应用
app = Flask(__name__)
app.config['SECRET_KEY'] = "b'pG\x05\x02pv\xcfGg\xd8\xb5\xaf\xe6\x05\xcc\xb40\xec\x8fZ2\x1bn\xfa'"
CORS(app)

# 数据库连接配置
def get_db_connection():
    return pymysql.connect(host='localhost',
                           user='root',
                           password='root',
                           db='personal_finance',
                           cursorclass=pymysql.cursors.DictCursor)


# JWT验证装饰器
def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        # 获取Authorization头部
        auth_header = request.headers.get('Authorization')

        if not auth_header:
            return jsonify({'message': 'Authorization header is missing!'}), 403
        
        # 尝试提取token部分
        parts = auth_header.split()
        if len(parts) != 2 or parts[0].lower() != 'bearer':
            return jsonify({'message': 'Authorization header must be a Bearer token!'}), 403

        token = parts[1]
        try:
            # 解码并验证JWT
            data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
            current_user_id = data['user_id']
        except jwt.ExpiredSignatureError:
            return jsonify({'message': 'Token has expired!'}), 401
        except jwt.InvalidTokenError:
            return jsonify({'message': 'Invalid token!'}), 401

        # 将解码后的用户ID传递给原始函数
        return f(current_user_id, *args, **kwargs)

    return decorated

# 用户管理API
def handle_options():
    response = jsonify({'message': 'OK'})
    response.headers['Access-Control-Allow-Origin'] = '*'  # 允许跨域访问，* 表示允许所有来源
    response.headers['Access-Control-Allow-Methods'] = 'POST'  # 允许 POST 方法
    response.headers['Access-Control-Allow-Headers'] = 'Content-Type'  # 允许 Content-Type 头部
    return response
# 用户注册
@app.route('/api/users/register', methods=['POST'])
def register():
    data = request.get_json()
    email = data.get('email')
    password = data.get('password')
    username = data.get('username')
    app.logger.info(f"Received registration data: {data}")


    # 数据验证代码（如检查邮箱格式和密码强度）
    # 数据验证
    if not re.match(r"[^@]+@[^@]+\.[^@]+", email):  # 简单的邮箱格式验证
        return jsonify({'message': '无效的邮箱地址'}), 400

    if len(password) < 6:  # 简单的密码长度验证
        return jsonify({'message': '密码长度至少为6个字符'}), 400
    # 加密密码
    password_hash = generate_password_hash(password)

    try:
        connection = get_db_connection()
        with connection.cursor() as cursor:
            # 检查邮箱是否已被注册
            cursor.execute("SELECT * FROM Users WHERE email = %s", (email,))
            if cursor.fetchone():
                return jsonify({'message': '邮箱已被注册'}), 409

            # 插入新用户
            sql = "INSERT INTO Users (username, email, password_hash) VALUES (%s, %s, %s)"
            cursor.execute(sql, (username, email, password_hash))
            connection.commit()
            app.logger.info("User registered successfully.")
        return jsonify({'message': '用户注册成功', 'username': username}), 201
    except Exception as e:
        return jsonify({'message': '注册失败', 'error': str(e)}), 500
    finally:
        if connection:
            connection.close()


#用户登陆
@app.route('/api/users/login', methods=['POST'])
def login():
    data = request.get_json()
    email = data.get('email')
    password = data.get('password')

    try:
        connection = get_db_connection()
        with connection.cursor() as cursor:
            cursor.execute("SELECT * FROM Users WHERE email = %s", (email,))
            user = cursor.fetchone()
            
            if user and check_password_hash(user['password_hash'], password):
                # 更新用户最新登录时间
                current_time = datetime.utcnow()
                cursor.execute("UPDATE Users SET last_login_date = %s WHERE user_id = %s", (current_time, user['user_id']))
                connection.commit()


                # 确保 user_id 是字符串
                user_id_str = str(user['user_id'])
                
                # 生成 JWT
                token = jwt.encode({
                    'user_id': user_id_str,
                    'username': user['username'],  # 将用户名添加到 JWT 有效负载中
                    'exp': datetime.utcnow() + timedelta(hours=24)
                }, app.config['SECRET_KEY'], algorithm="HS256")

                return jsonify({'token': token, 'username': user['username']}), 200
            else:
                return jsonify({'message': '邮箱或密码错误'}), 401
    except Exception as e:
        app.logger.error(f"登录过程中发生错误: {e}")
        return jsonify({'message': '内部服务器错误'}), 500
    finally:
        if connection:
            connection.close()


# 交易管理API
#添加交易
@app.route('/api/transactions', methods=['POST'])
@token_required
def add_transaction(current_user_id):
    data = request.get_json()
    # 获取并验证数据
    type = data.get('type')  # "income" 或 "expense"
    amount = data.get('amount')
    category = data.get('category', '')  # 可选分类
    description = data.get('description', '')  # 可选描述

    # 数据库操作
    try:
        connection = get_db_connection()
        with connection.cursor() as cursor:
            sql = "INSERT INTO Transactions (user_id, type, amount, category, description) VALUES (%s, %s, %s, %s, %s)"
            cursor.execute(sql, (current_user_id, type, amount, category, description))
            connection.commit()
        return jsonify({'message': '交易添加成功'}), 201
    except Exception as e:
        return jsonify({'message': f'交易添加失败: {e}'}), 500
    finally:
        if connection:
            connection.close()


#获取交易
@app.route('/api/transactions', methods=['GET'])
@token_required
def get_transactions(current_user_id):
    try:
        connection = get_db_connection()
        with connection.cursor() as cursor:
            cursor.execute("SELECT * FROM Transactions WHERE user_id = %s", (current_user_id,))
            transactions = cursor.fetchall()
        return jsonify(transactions), 200
    except Exception as e:
        return jsonify({'message': '获取交易失败'}), 500
    finally:
        if connection:
            connection.close()

#更改交易
@app.route('/api/transactions/<int:transaction_id>', methods=['PUT'])
@token_required
def update_transaction(current_user_id, transaction_id):
    data = request.get_json()
    # 获取并验证数据
    type = data.get('type')
    amount = data.get('amount')
    category = data.get('category', '')
    description = data.get('description', '')

    try:
        connection = get_db_connection()
        with connection.cursor() as cursor:
            # 检查交易是否存在并且属于当前用户
            cursor.execute("SELECT * FROM Transactions WHERE transaction_id = %s AND user_id = %s", (transaction_id, current_user_id))
            transaction = cursor.fetchone()

            if not transaction:
                return jsonify({'message': '交易不存在或无权访问'}), 404

            # 更新交易
            sql = "UPDATE Transactions SET type=%s, amount=%s, category=%s, description=%s WHERE transaction_id=%s"
            cursor.execute(sql, (type, amount, category, description, transaction_id))
            connection.commit()

        return jsonify({'message': '交易更新成功'}), 200
    except Exception as e:
        return jsonify({'message': '交易更新失败', 'error': str(e)}), 500
    finally:
        if connection:
            connection.close()

#删除交易
@app.route('/api/transactions/<int:transaction_id>', methods=['DELETE'])
@token_required
def delete_transaction(current_user_id, transaction_id):
    try:
        connection = get_db_connection()
        with connection.cursor() as cursor:
            # 首先检查交易是否存在并且属于当前用户
            cursor.execute("SELECT * FROM Transactions WHERE transaction_id = %s AND user_id = %s", (transaction_id, current_user_id))
            transaction = cursor.fetchone()

            if not transaction:
                return jsonify({'message': '交易不存在或无权访问'}), 404

            # 删除交易
            sql = "DELETE FROM Transactions WHERE transaction_id = %s"
            cursor.execute(sql, (transaction_id,))
            connection.commit()

        return jsonify({'message': '交易删除成功'}), 200
    except Exception as e:
        return jsonify({'message': '交易删除失败', 'error': str(e)}), 500
    finally:
        if connection:
            connection.close()

# 预选管理api
# 增加预算
@app.route('/api/budgets', methods=['POST'])
@token_required
def add_budget(current_user_id):
    data = request.get_json()
    amount = data.get('amount')
    start_date = data.get('start_date')
    end_date = data.get('end_date')
    category = data.get('category', '')  # 假设类别是可选的
    description = data.get('description', '')

    # 数据验证
    if not all([amount, start_date, end_date]):
        return jsonify({'message': '缺少必要的预算信息'}), 400

    # 验证金额是否为有效数值
    try:
        amount = float(amount)
    except ValueError:
        return jsonify({'message': '无效的金额'}), 400

    # 验证日期格式及逻辑
    try:
        start_date = datetime.strptime(start_date, '%Y-%m-%d').date()
        end_date = datetime.strptime(end_date, '%Y-%m-%d').date()
        if end_date <= start_date:
            return jsonify({'message': '结束日期必须晚于开始日期'}), 400
    except ValueError:
        return jsonify({'message': '无效的日期格式'}), 400

    try:
        # 数据库操作封装到一个函数中
        add_budget_to_db(current_user_id, amount, start_date, end_date, category, description)
        return jsonify({'message': '预算添加成功'}), 201
    except Exception as e:
        return jsonify({'message': '预算添加失败', 'error': str(e)}), 500

def add_budget_to_db(user_id, amount, start_date, end_date, category, description):
    connection = get_db_connection()
    try:
        with connection.cursor() as cursor:
            sql = """
            INSERT INTO Budgets 
            (user_id, amount, start_date, end_date, category, description) 
            VALUES (%s, %s, %s, %s, %s, %s)
            """
            cursor.execute(sql, (user_id, amount, start_date, end_date, category, description))
            connection.commit()
    finally:
        if connection:
            connection.close()

# 查询预算
@app.route('/api/budgets', methods=['GET'])
@token_required
def get_budgets(current_user_id):
    try:
        budgets = fetch_user_budgets(current_user_id)
        budget_list = format_budgets(budgets)
        return jsonify(budget_list), 200
    except Exception as e:
        return jsonify({'message': '获取预算失败', 'error': str(e)}), 500

def fetch_user_budgets(user_id):
    with get_db_connection() as connection:
        with connection.cursor() as cursor:
            # 查询当前授权用户的所有预算
            sql = "SELECT * FROM Budgets WHERE user_id = %s"
            cursor.execute(sql, (user_id,))
            return cursor.fetchall()

def format_budgets(budgets):
    budget_list = []
    for budget in budgets:
        budget_list.append({
            'budget_id': budget['budget_id'],
            'user_id': budget['user_id'],
            'amount': float(budget['amount']),
            'start_date': budget['start_date'].strftime('%Y-%m-%d'),
            'end_date': budget['end_date'].strftime('%Y-%m-%d'),
            'category': budget['category'],
            'description': budget['description']
        })
    return budget_list


#更新预算
@app.route('/api/budgets/<int:budget_id>', methods=['PUT'])
@token_required
def update_budget(current_user_id, budget_id):
    data = request.get_json()
    amount = data.get('amount')
    start_date = data.get('start_date')
    end_date = data.get('end_date')
    category = data.get('category')
    description = data.get('description')

    if not all([amount, start_date, end_date]):
        return jsonify({'message': '缺少必要的预算信息'}), 400

    try:
        # 验证并转换输入
        amount = float(amount)
        start_date = datetime.strptime(start_date, '%Y-%m-%d').date()
        end_date = datetime.strptime(end_date, '%Y-%m-%d').date()
        if end_date <= start_date:
            return jsonify({'message': '结束日期必须晚于开始日期'}), 400
    except (ValueError, TypeError):
        return jsonify({'message': '无效的输入'}), 400

    try:
        updated = update_budget_in_db(current_user_id, budget_id, amount, start_date, end_date, category, description)
        if not updated:
            return jsonify({'message': '未找到对应的预算记录或无权更新'}), 404

        return jsonify({'message': '预算更新成功'}), 200
    except Exception as e:
        return jsonify({'message': '预算更新失败', 'error': str(e)}), 500

def update_budget_in_db(user_id, budget_id, amount, start_date, end_date, category, description):
    with get_db_connection() as connection:
        with connection.cursor() as cursor:
            sql = """
            UPDATE Budgets 
            SET amount = %s, start_date = %s, end_date = %s, category = %s, description = %s
            WHERE budget_id = %s AND user_id = %s
            """
            cursor.execute(sql, (amount, start_date, end_date, category, description, budget_id, user_id))
            connection.commit()
            return cursor.rowcount > 0


#删除预算
@app.route('/api/budgets/<int:budget_id>', methods=['DELETE'])
@token_required
def delete_budget(current_user_id, budget_id):
    try:
        deleted = delete_budget_from_db(current_user_id, budget_id)
        if not deleted:
            return jsonify({'message': '未找到对应的预算记录或无权删除'}), 404

        return jsonify({'message': '预算删除成功'}), 200
    except Exception as e:
        return jsonify({'message': '预算删除失败', 'error': str(e)}), 500

def delete_budget_from_db(user_id, budget_id):
    with get_db_connection() as connection:
        with connection.cursor() as cursor:
            # 确保只有拥有该预算记录的用户可以删除它
            sql = "DELETE FROM Budgets WHERE budget_id = %s AND user_id = %s"
            cursor.execute(sql, (budget_id, user_id))
            connection.commit()
            return cursor.rowcount > 0


# 运行Flask应用
if __name__ == '__main__':
    app.run(debug=True)
